package com.bms.cfcmms.dao;


import com.bms.cfcmms.core.module.SqlGenerator;
import com.bms.cfcmms.core.util.Utils;
import com.bms.cfcmms.model.system.module.Module;
import com.bms.cfcmms.util.SysUtils;
import com.bms.cfcmms.core.module.SqlType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.sql.DataSource;

/**
 * Created by carl on 2016/4/9.
 */
public class BaseDao<T extends Serializable> {

    private final Logger log = LoggerFactory.getLogger(BaseDao.class);
    protected NamedParameterJdbcTemplate namedTemplate;

    @Resource
    protected ModuleDao moduleDao;

    @Autowired
    public void setDataSource(DataSource dataSource) {
        this.namedTemplate = new NamedParameterJdbcTemplate(dataSource);
    }

    /**
     * 对象实例更新.
     * <p>
     * <p>使用对象实例更新实体的通用方法</p>
     *
     * @param object 更新的实体
     * @param module 实体对应的Module对象
     * @return 更新记录的主键值
     */
    public int updateEntity(T object, Module module) {

        SqlGenerator sqlGen = Utils.getSqlGenerator(SqlType.UPDATE, object, module);
        String sql = sqlGen.makeSql();
        SqlParameterSource sqlParameter = new BeanPropertySqlParameterSource(object);
        return this.namedTemplate.update(sql, sqlParameter);
    }

    /**
     * 查找某条记录.
     * <p>
     * 通过ID主键来查找某条记录的通用方法
     * </p>
     *
     * @param id     查找记录的主键
     * @param module 查找对象的Module对象
     * @return 返回相应的对象
     */
    public T queryForObjectById(Object id, Module module) {

        T obj = null;
        StringBuilder sqlBuf = new StringBuilder(SqlType.SELECTALL);
        String tableName = findRealTableName(module);
        sqlBuf.append(tableName);

        sqlBuf.append(SqlType.WHERE);
        sqlBuf.append(module.getPrimaryKey());
        sqlBuf.append("=:").append(module.getPrimaryKey());

        log.info("操作语句为：" + sqlBuf.toString());
        Class refClass = getClass();

        Object operObj = SysUtils.getClassObj(refClass);

        if (operObj == null) {
            log.error("没有获取到queryForObject方法中的第三个参数!");
            return obj;
        }
        Class<T> tClass = (Class<T>)operObj;
        SqlParameterSource sqlParameterSource = new MapSqlParameterSource(
                module.getPrimaryKey(), id);
        try {
            obj = this.namedTemplate.queryForObject(
                    sqlBuf.toString(), sqlParameterSource, (RowMapper<T>) tClass.newInstance());
        } catch (Exception e) {
            log.error("", e);
        }
        return obj;
    }

    /**
     * 查询所有数据.
     *
     * @param module 模块相关信息
     * @return 一个list的集合
     */
    public List<T> queryAllData(Module module) {
        List<T> result = new ArrayList<>();
        String tableName = findRealTableName(module);
        String sql = SqlType.SELECTALL + tableName;
        Class refClass = getClass();
        Object operObj = SysUtils.getClassObj(refClass);

        Class<T> tClass = (Class<T>)operObj;
        try {
            result = namedTemplate.query(sql, (RowMapper<T>) tClass.newInstance());
        } catch (Exception e) {
            log.error("在查询所有数据的过程中出现了异常", e);
        }

        return result;
    }

    /**
     * 找到真正的表名.
     *
     * @param module 模块信息
     * @return 表名
     */
    public String findRealTableName(Module module) {
        String tableName = module.getTableName();
        if (tableName == null) {
            tableName = module.getModuleName();
        }
        return tableName;
    }

    /**
     * 查询数据.
     * <p>
     * <p>根据对象主键之外的其它参数来查询数据
     * 参数obj中保存的是查询条件.
     * </p>
     *
     * @param obj 查询的对象的实例
     * @return 返回一个对象数组
     */
    public List<T> queryForObject(T obj, Module module) {

        SqlGenerator sqlGen = Utils.getSqlGenerator(SqlType.SELECT, obj, module);
        String sql = sqlGen.makeSql();
        SqlParameterSource sqlParameter = new BeanPropertySqlParameterSource(obj);

        return getResultObjects(obj.getClass(), sql, sqlParameter);
    }

    private List<T> getResultObjects(Class obj, String sql, SqlParameterSource sqlParameter) {
        List<T> result = new ArrayList<>();
        try {
            result = this.namedTemplate.query(sql, sqlParameter,
                    (RowMapper<T>) obj.newInstance());
        } catch (InstantiationException e) {
            log.error("", e);
        } catch (IllegalAccessException e) {
            log.error("", e);
        }
        return result;
    }

    public List<T> queryDataByParamer(Class<T> obj, String tableName, String paramerName,
                                           Object value) {
        String sql = SqlType.SELECTALL + tableName + SqlType.WHERE + paramerName + " =:" + paramerName;
        SqlParameterSource sqlParameterSource = new MapSqlParameterSource(paramerName, value);
        return getResultObjects(obj, sql, sqlParameterSource);
    }

    /**
     * 删除某条记录.
     * <p>
     * <p>通过ID主键来删除一条记录信息</p>
     *
     * @param id     数据库记录主键
     * @param module 记录对应的_Module对象
     * @return 删除记录对应的主键信息
     */
    public int delete(Object id, Module module) {
        String sql = "delete from "
                + findRealTableName(module)
                + SqlType.WHERE + module.getPrimaryKey()
                + "=:" + module.getPrimaryKey();
        SqlParameterSource sqlParameterSource = new MapSqlParameterSource(
                module.getPrimaryKey(), id);

        return this.namedTemplate.update(sql, sqlParameterSource);
    }

    /**
     * 保存数据到表中.
     *
     * @param object    要保存的数据
     * @param tableName 表名
     * @return 记录的ID号
     */
    public Integer save(T object, String tableName) {
        SqlGenerator sqlGen = Utils.getSqlGenerator(SqlType.INSERT, object, tableName);

        String sql = sqlGen.makeSql();
        SqlParameterSource sqlParameter = new BeanPropertySqlParameterSource(object);

        KeyHolder keyholder = new GeneratedKeyHolder();
        try {
            this.namedTemplate.update(sql, sqlParameter, keyholder);
        } catch (Exception e){
            log.error("", e);
        }

        //加上KeyHolder这个参数可以得到添加后主键的值（只限于自动增长的主键 ）
        if (keyholder.getKey() == null) {
            return 0;
        } else {
            return keyholder.getKey().intValue();
        }
        //Map map=keyholder.getKeys();//这样可以得到联合主键的值
        //keyholder.getKeyList();//这样可以得到一些主主键值，若一次添加好几条记录
    }

    /**
     * 删除一个实体对象.
     *
     * @param obj  删除的对象信息
     * @param module  对象对应的模块信息
     */
    public Integer deleteByObject(T obj, Module module) {
        SqlGenerator sqlGen = Utils.getSqlGenerator(SqlType.DELETE, obj, module);
        String sql = sqlGen.makeSql();

        SqlParameterSource sqlParameter = new BeanPropertySqlParameterSource(obj);
        return this.namedTemplate.update(sql, sqlParameter);
    }
}
